package com.lemurian.bankdata.action.base;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.struts2.ServletActionContext;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

import com.lemurian.bankdata.dto.LogHelper;
import com.lemurian.bankdata.lite.authentication.BankDataPrincipal;
import com.lemurian.bankdata.lite.enums.ApplicationCategory;
import com.lemurian.bankdata.lite.enums.UserActivityType;
import com.lemurian.bankdata.lite.enums.UserStatus;
import com.lemurian.bankdata.lite.logger.BankDataLogger;
import com.lemurian.bankdata.lite.struts.Pager;
import com.lemurian.bankdata.lite.struts.PartialList;
import com.lemurian.bankdata.lite.utils.BankDataCommons;
import com.lemurian.bankdata.lite.utils.Encryption;
import com.lemurian.bankdata.lite.utils.FormatData;
import com.lemurian.bankdata.lite.utils.GeneralConstant;
import com.lemurian.bankdata.lite.utils.GlobalFunction;
import com.lemurian.bankdata.services.ActivityLogService;
import com.lemurian.bankdata.services.CategoryService;
import com.lemurian.bankdata.services.GroupsService;
import com.lemurian.bankdata.services.UserService;
import com.lemurian.bankdata.utils.BaseAction;
import com.lemurian.entity.Category;
import com.lemurian.entity.Groups;
import com.lemurian.entity.User;
import com.opensymphony.xwork2.Preparable;

public class UserAction extends BaseAction implements Preparable {

	private static final long serialVersionUID = 8990580091694829481L;

	private BankDataLogger log = BankDataLogger.getLogger(UserAction.class.getSimpleName());
	
	private User user = new User();
	private List<User> users;
	
	private String birthDate;
	
	private int userTypeId = 0;
	private List<Category> userTypes = new ArrayList<Category>();
	
	private int departmentId = 0;
	private List<Category> departments = new ArrayList<Category>();
	
	private int[] groupIdList;
	private List<Groups> userGroups = new ArrayList<Groups>();
	
	private int id = 0;
	
	private User sessionUser;
	private BankDataPrincipal principal;
	
	@Autowired private UserService userService;
	@Autowired private CategoryService categoryService;
	@Autowired private GroupsService groupsService;
	
	@Autowired 
	private ActivityLogService userActivityLogService;
	private LogHelper userActivityLog;
	
	@Override
	public void prepare() throws Exception {
		principal = (BankDataPrincipal) getSession().get(GeneralConstant.USER_PRINCIPAL);
		sessionUser = principal.getUser();
		
		if(id > 0) {
			setReadOnly(Boolean.TRUE);
			user = userService.load(id);
			
			if(getUser().getBirthDate()!=null) {
				birthDate = FormatData.dateFormatShow.format(getUser().getBirthDate());
			}
			
			if(getUser().getUserType() != null) {
				userTypeId = user.getUserType().getId();
			}
			
			if(getUser().getDepartment() != null) {
				departmentId = user.getDepartment().getId();
			}
			
			if (user.getGroups() !=null && user.getGroups().size()>0) {
				Iterator<Groups> iterator = user.getGroups().iterator();
				groupIdList = new int[user.getGroups().size()];
				int i=0;
				while (iterator.hasNext()) {
					Groups role = (Groups)iterator.next();
					groupIdList[i] = role.getId();
					i++;
				}
			}
		}
	}
	
	@Override
	public String list() {
		log.info("list User");

        setPreviousPage(GeneralConstant.LIST);
        try {

            PartialList<User> partialList = userService.findByCriteria(getStart(), getCount(),
                    getAscDesc().equalsIgnoreCase("desc") ? Order.desc(getOrderBy().length() > 0 ? getOrderBy() : "id") : Order.asc(getOrderBy().length() > 0 ? getOrderBy() : "name"),
                    user.getName() != null && user.getName().length() > 0 ? Restrictions.ilike("name", user.getName(), MatchMode.ANYWHERE) : Restrictions.ne("id", new Integer(-1)),
                    user.getEmail() != null && user.getEmail().length() > 0 ? Restrictions.ilike("email", user.getEmail(), MatchMode.ANYWHERE) : Restrictions.ne("id", new Integer(-1))//,
                    //Restrictions.eq("status", 'A')
                    );

            users = partialList.getList();
            
            log.info(": : : : : USER SIZE : "+users.size());

            setPager(Pager.generatePager(getStart(), getCount(), partialList.getTotal()));
            setPagerItem(Pager.generatePagerItem(getStart(), getCount(), partialList.getTotal()));

            partialList = null;
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        setMappedRequest(GeneralConstant.LIST);
        return SUCCESS;
	}
	
	@Override
	public String add() {
		setPreviousPage(GeneralConstant.ADD);
		setMappedRequest(GeneralConstant.SAVE);
		
		userTypes = categoryService.findByCriteria(Order.asc("id"),(Restrictions.eq("parent.id", ApplicationCategory.USER_TYPES.code())));
		
		departments = categoryService.findByCriteria(Order.asc("id"),(Restrictions.eq("parent.id", ApplicationCategory.TIPE_DEPARTEMEN.code()))); 
		
		userGroups = groupsService.findAll();
		
		getSession().put(GeneralConstant.TIME_IN_SESSION, new Date());
		
		return SUCCESS;
	}
	
	@Override
	public String save() {
		try {
			
			String message = "";
			if(id > 0) {
				user.setUpdateBy(sessionUser.getName());
				user.setUpdateDate(new Timestamp(System.currentTimeMillis()));
				
				message = "Update";
				userActivityLog = new LogHelper(sessionUser, UserActivityType.UPDATE_USER);
			} else {
				user.setCreateBy(sessionUser.getName());
				user.setCreateDate(new Timestamp(System.currentTimeMillis()));
				
				message = "Add";
				userActivityLog = new LogHelper(sessionUser, UserActivityType.ADD_USER);
			}
			
			if (groupIdList.length > 0) {
				user.getGroups().clear();
				userService.save(user);
				
				for (int i=0; i<groupIdList.length; i++) {
					Groups group = groupsService.findById(groupIdList[i]);
					user.getGroups().add(group);
				}
			}
			
			if(birthDate != null && !birthDate.equalsIgnoreCase("")) {
				user.setBirthDate(FormatData.dateFormatShow.parse(birthDate));
			}
			
			Category category = categoryService.findById(userTypeId);
			
			log.info(": : : : : USER TYPE TYPE  : "+userTypeId);
			log.info(": : : : : USER TYPE       : "+category);
			
			if(category != null) {
				user.setUserType(category);
			}
			
			category = categoryService.findById(departmentId);
			
			log.info(": : : : : DEPARTMENT ID : "+departmentId);
			log.info(": : : : : DEPARTMENT    : "+category);
			
			if(category != null) {
				user.setDepartment(category);
			}
			
			user.setPassword(Encryption.SHA1(BankDataCommons.getBankDataConfig().getString("default.newuserpassword")));
			user.setStatus(UserStatus.ACTIVE.code());
			user.setPasswordValidDate(new Date());
			
			userService.save(user);
			
			try {
                message += " " + user.getName() + " is success";
                addCustomActionMessage(message);
                
                log.sInfo(" :: User [%s:%s] is successfully save User [%s:%s]", sessionUser.getId(), sessionUser.getName(), user.getId(), user.getName());
                userActivityLog.setStatus(LogHelper.SUCCESS_ACTIVITY);
            } catch (Exception e) {
                message += " " + user.getName() + " is failed, message : "+e.getMessage();
                addCustomActionError(message);
                log.sInfo(" :: Error was raised when User [%s:%s] save User [%s:%s]", sessionUser.getId(), sessionUser.getName(), user.getId(), user.getName());
                
                //set activity log status into failed
                userActivityLog.setStatus(LogHelper.FAILED_ACTIVITY);
                userActivityLog.setErrorMsg(e.getMessage());
            }
            
            userActivityLog.setSessionId(ServletActionContext.getRequest().getSession().getId());
            userActivityLog.setStartDate((Date) getSession().get(GeneralConstant.TIME_IN_SESSION));
            userActivityLog.getAdditionalParams().add(user.getName());
            userActivityLogService.saveUserActivity(userActivityLog);
            getSession().remove(GeneralConstant.TIME_IN_SESSION);
			
		} catch (Throwable t) {
			addCustomActionError(t.getMessage());
			t.printStackTrace();
		}
		
		setMappedRequestFullPath("/UserAction_list.do");
		return GeneralConstant.REDIRECT;
	}

	@Override
	public String delete() {
		try {
			userService.delete(id);
			
			userActivityLog = new LogHelper(user, UserActivityType.DELETE_USER);
			
			String message = "";
            try {
                message = "Delete " + user.getName() + " is success";
                addCustomActionMessage(message);
                log.sInfo(" :: User [%s:%s] is successfully delete User [%s:%s]", sessionUser.getId(), sessionUser.getName(), user.getId(), user.getName());

                //check if activity is success
                userActivityLog.setStatus(LogHelper.SUCCESS_ACTIVITY);
            } catch (Exception e) {
                message = "Delete " + user.getName() + " is failed, message : "+e.getMessage();
                addCustomActionError(message);
                log.sInfo(" :: Error was raised when User [%s:%s] delete [%s:%s]", sessionUser.getId(), sessionUser.getName(), user.getId(), user.getName());
                
                //set activity log status into failed
                userActivityLog.setStatus(LogHelper.FAILED_ACTIVITY);
                userActivityLog.setErrorMsg(e.getMessage());
            }
            //save activity log
            userActivityLog.getAdditionalParams().add(user.getName());
            userActivityLogService.saveUserActivity(userActivityLog);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		setMappedRequestFullPath("/UserAction_list.do");
		return GeneralConstant.REDIRECT;
	}

	@Override
	public String detail() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public String edit() {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String update() {
		// TODO Auto-generated method stub
		return null;
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public String getBirthDate() {
		return birthDate;
	}

	public void setBirthDate(String birthDate) {
		this.birthDate = birthDate;
	}

	public int getUserTypeId() {
		return userTypeId;
	}

	public void setUserTypeId(String userTypeId) {
		int id_ = 0;
		if(userTypeId != null && !userTypeId.equalsIgnoreCase("0")) {
			userTypeId = GlobalFunction.decodeParameter(userTypeId);
	        id_ = Integer.parseInt(userTypeId);
		}
        this.userTypeId = id_;
	}

	public List<Category> getUserTypes() {
		return userTypes;
	}

	public void setUserTypes(List<Category> userTypes) {
		this.userTypes = userTypes;
	}

	public int[] getGroupIdList() {
		return groupIdList;
	}

	public void setGroupIdList(int[] groupIdList) {
		this.groupIdList = groupIdList;
	}

	public List<Groups> getUserGroups() {
		return userGroups;
	}

	public void setUserGroups(List<Groups> userGroups) {
		this.userGroups = userGroups;
	}

	public int getId() {
		return id;
	}

	public void setId(String id) {
		int id_ = 0;
		if(id != null && !id.equalsIgnoreCase("0")) {
			id = GlobalFunction.decodeParameter(id);
	        id_ = Integer.parseInt(id);
		}
        this.id = id_;
	}

	public int getDepartmentId() {
		return departmentId;
	}

	public void setDepartmentId(String departmentId) {
		int id_ = 0;
		if(departmentId != null && !departmentId.equalsIgnoreCase("0")) {
			departmentId = GlobalFunction.decodeParameter(departmentId);
	        id_ = Integer.parseInt(departmentId);
		}
        this.departmentId = id_;
	}

	public List<Category> getDepartments() {
		return departments;
	}

	public void setDepartments(List<Category> departments) {
		this.departments = departments;
	}
	
}